The purpose of this lab is to add the IMU to your robot, start running the Artemis+sensors from a battery, and record a stunt on your RC robot.
Setup the IMU
We used the code below to calculate pitch, roll and yaw using data from IMU.
myICM.getAGMT(); // The values are only updated when you call 'getAGMT'
// printRawAGMT( myICM.agmt ); // Uncomment this to see the raw values, taken directly from the agmt structure
//printScaledAGMT(&myICM); // This function takes into account the scale settings from when the measurement was made to calculate the values with units
//delay(30);
//calculate the pitch and roll
//yaw_g = yaw_g + myICM.gyrZ()*dt;
//delay(10); //ms
dt = (millis()-last_time)/100000.;
// Serial.println(millis());
// Serial.println(last_time);
last_time = millis();
pitch_a = atan2(myICM.accY(),myICM.accZ())*180/M_PI;
pitch_g = pitch_g + myICM.gyrX()*dt;
pitch = (pitch+myICM.gyrX()*dt)*0.9 + pitch_a*0.1;
roll_a = atan2(myICM.accX(),myICM.accZ())*180/M_PI;
roll_g = roll_g + myICM.gyrY()*dt;
roll = (roll+myICM.gyrY()*dt)*0.9 + roll_a*0.1;
Xm = myICM.magX();
Ym = myICM.magY();
Zm = myICM.magZ();
x = Ym*cos(roll*M_PI/180) - Zm*sin(roll*M_PI/180);
y = Xm*cos(pitch*M_PI/180) + Ym*sin(roll*M_PI/180)*sin(pitch*M_PI/180) + Zm*cos(roll*M_PI/180)*sin(pitch*M_PI/180);
yaw = atan2(y,x)*180/M_PI;
Show the output at {-90, 0, 90} degrees pitch and roll. Hint: You can use the surface and edges of your table as guides to ensure 90 degree tilt/roll.
As demonstrated in the figure below, when we make the IMU flat on the table the pitch and roll parameters are all close to zero.
When we turned the IMU along the y-axis for 90 degrees, the pitch data has increased to around 8.6 and the roll data still closed to 0.
Conversely, if we turned the IMU around the y-axis for negative 90 degrees (shown in the figure below), the pitch parameter turned to around -8.6 with roll still close to 0.
Same for the roll, when we turned the IMU along x-axis for 90 degrees, the roll parameter became close to 8.6 and the pitch kept closed to 0.
And the roll data are around -8.6 after we turned the IMU along the inverse direction.
The accelerometer is noisy, especially when you run the RC car in its proximity. Record some of this data, and analyze the noise in the frequency spectrum.
The figure below shows the IMU signal in the time domain (upper) and the frequency domain (lower) when we hit the table to make some noise. from the frequency domain, it is noticeable that there are some fluctuations in the part above 50 Hz, which is not the signal frequency that can be generated by operation on the IMU. (Suppose you turn the IMU 50 times per second, that is crazy!)
To reduce the noise signal which has a high frequency, we designed a Low-Pass Filter. This filter can block the high-frequency noise to make the signal more accurate and easier to use in the future steps.
The results after adding the LPF is shown above, which is noticeable that there is little fluctuations in the high-frequency region, most of the signal is in the region from 0Hz to 50Hz, which is what we want from this IMU.
Compare your output to the pitch, roll, and yaw values from the accelerometer and the filtered response. Describe how they differ.
As shown in the figure below, in the serial output, the first column is the pitch value calculated from the accelerator and the second column is the pitch value calculaed from the gyroscope value. It is obvious that the accelerator value is larger than the gyroscope value.
Also for the roll value, the data from the accelerator is larger than that from the gyroscope.
Try adjusting the sampling frequency to see how it changes the accuracy of your estimated angles.
Here we added a 10ms delay for each purch and roll value. From the figure below we could notice that the data is becoming more inaccurate because the value of pitch and roll fluctuate a lot even when we do not move the IMU.
Use a complimentary filter to compute an estimate of pitch and roll which is both accurate and stable. Demonstrate its working range and accuracy, and that it is not susceptible to drift or quick vibrations.
Here attached is the code and result of the complimentary filter, we make our final value 90% from the gyroscope and 10% from the accelerator. This is because in the experiment we found that the time unit of the accelerator and the gyroscope is different. When we use the same time unit for both of the methods, the gyroscope's results are around 10 while the results from the accelerator are over 100.
From the plot in the figure above we can notice that the pitch and roll value become very smooth after implementing the complimentary filter.
Similar to Lab 1, collect and store time-stamped IMU data in arrays. Do this in your main loop using flags to start/stop data recording.
Here below is the code instructing how we store and send timestamp and pitch/roll data
Demonstrate that your board can capture at least 5s worth of IMU data and send it over Bluetooth to the computer.
Demonstrate that your board can capture at least 5s worth of IMU data and send it over Bluetooth to the computer.
The figure below shows how the arduino is collecting, storing and sending IMU data. It also gives instruction about how our computer could receive the data using callback function in jupyter notebook. And we can notice that the IMU data are fully collected, stored, sent and received since the data printed in the jupyter notebook are also has a 3ms interval.
Here below shows the full results for the 5s data, it could be very long and you may just skip.
This is the end of this Lab!
time: 242958.0 pitch_acc: 30.364 pitch_gry: 0.976
time: 242962.0 pitch_acc: 30.258 pitch_gry: 0.976
time: 242965.0 pitch_acc: 30.357 pitch_gry: 0.976
time: 242972.0 pitch_acc: 30.284 pitch_gry: 0.976
time: 242974.0 pitch_acc: 30.67 pitch_gry: 0.976
time: 242977.0 pitch_acc: 30.856 pitch_gry: 0.976
time: 242984.0 pitch_acc: 30.417 pitch_gry: 0.976
time: 242987.0 pitch_acc: 30.3 pitch_gry: 0.976
time: 242990.0 pitch_acc: 30.181 pitch_gry: 0.976
time: 242993.0 pitch_acc: 29.662 pitch_gry: 0.976
time: 242997.0 pitch_acc: 30.500 pitch_gry: 0.976
time: 243000.0 pitch_acc: 29.956 pitch_gry: 0.976
time: 243005.0 pitch_acc: 30.33 pitch_gry: 0.976
time: 243008.0 pitch_acc: 31.151 pitch_gry: 0.976
time: 243010.0 pitch_acc: 30.326 pitch_gry: 0.976
time: 243018.0 pitch_acc: 31.248 pitch_gry: 0.976
time: 243023.0 pitch_acc: 29.649 pitch_gry: 0.976
time: 243026.0 pitch_acc: 30.378 pitch_gry: 0.976
time: 243028.0 pitch_acc: 29.409 pitch_gry: 0.976
time: 243031.0 pitch_acc: 30.149 pitch_gry: 0.976
time: 243034.0 pitch_acc: 30.518 pitch_gry: 0.976
time: 243037.0 pitch_acc: 30.595 pitch_gry: 0.976
time: 243040.0 pitch_acc: 30.188 pitch_gry: 0.976
time: 243046.0 pitch_acc: 29.753 pitch_gry: 0.976
time: 243049.0 pitch_acc: 30.25 pitch_gry: 0.976
time: 243053.0 pitch_acc: 30.666 pitch_gry: 0.976
time: 243056.0 pitch_acc: 30.289 pitch_gry: 0.976
time: 243058.0 pitch_acc: 29.830 pitch_gry: 0.976
time: 243063.0 pitch_acc: 30.98 pitch_gry: 0.976
time: 243066.0 pitch_acc: 30.649 pitch_gry: 0.976
time: 243070.0 pitch_acc: 29.424 pitch_gry: 0.976
time: 243073.0 pitch_acc: 30.271 pitch_gry: 0.976
time: 243075.0 pitch_acc: 30.522 pitch_gry: 0.976
time: 243078.0 pitch_acc: 30.402 pitch_gry: 0.976
time: 243082.0 pitch_acc: 30.642 pitch_gry: 0.976
time: 243085.0 pitch_acc: 29.851 pitch_gry: 0.976
time: 243087.0 pitch_acc: 30.538 pitch_gry: 0.976
time: 243094.0 pitch_acc: 31.125 pitch_gry: 0.976
time: 243097.0 pitch_acc: 30.276 pitch_gry: 0.976
time: 243100.0 pitch_acc: 30.550 pitch_gry: 0.976
time: 243103.0 pitch_acc: 30.599 pitch_gry: 0.976
time: 243109.0 pitch_acc: 29.744 pitch_gry: 0.976
time: 243112.0 pitch_acc: 30.568 pitch_gry: 0.975
time: 243120.0 pitch_acc: 29.429 pitch_gry: 0.975
time: 243122.0 pitch_acc: 30.123 pitch_gry: 0.975
time: 243130.0 pitch_acc: 30.36 pitch_gry: 0.975
time: 243133.0 pitch_acc: 30.62 pitch_gry: 0.975
time: 243137.0 pitch_acc: 30.516 pitch_gry: 0.975
time: 243139.0 pitch_acc: 29.822 pitch_gry: 0.975
time: 243146.0 pitch_acc: 30.815 pitch_gry: 0.975
time: 243149.0 pitch_acc: 30.336 pitch_gry: 0.975
time: 243156.0 pitch_acc: 30.662 pitch_gry: 0.975
time: 243159.0 pitch_acc: 29.666 pitch_gry: 0.975
time: 243161.0 pitch_acc: 30.922 pitch_gry: 0.975
time: 243165.0 pitch_acc: 30.204 pitch_gry: 0.975
time: 243168.0 pitch_acc: 30.218 pitch_gry: 0.975
time: 243174.0 pitch_acc: 30.213 pitch_gry: 0.975
time: 243177.0 pitch_acc: 30.605 pitch_gry: 0.975
time: 243184.0 pitch_acc: 30.181 pitch_gry: 0.975
time: 243186.0 pitch_acc: 29.950 pitch_gry: 0.975
time: 243190.0 pitch_acc: 30.197 pitch_gry: 0.975
time: 243193.0 pitch_acc: 30.792 pitch_gry: 0.975
time: 243195.0 pitch_acc: 30.999 pitch_gry: 0.975
time: 243202.0 pitch_acc: 30.531 pitch_gry: 0.975
time: 243205.0 pitch_acc: 30.60 pitch_gry: 0.975
time: 243211.0 pitch_acc: 30.357 pitch_gry: 0.975
time: 243214.0 pitch_acc: 29.684 pitch_gry: 0.975
time: 243221.0 pitch_acc: 31.52 pitch_gry: 0.975
time: 243223.0 pitch_acc: 29.848 pitch_gry: 0.975
time: 243227.0 pitch_acc: 29.731 pitch_gry: 0.975
time: 243230.0 pitch_acc: 30.577 pitch_gry: 0.975
time: 243232.0 pitch_acc: 30.532 pitch_gry: 0.975
time: 243239.0 pitch_acc: 30.38 pitch_gry: 0.975
time: 243242.0 pitch_acc: 30.981 pitch_gry: 0.975
time: 243248.0 pitch_acc: 29.861 pitch_gry: 0.975
time: 243251.0 pitch_acc: 30.279 pitch_gry: 0.974
time: 243258.0 pitch_acc: 29.997 pitch_gry: 0.975
time: 243261.0 pitch_acc: 30.463 pitch_gry: 0.975
time: 243265.0 pitch_acc: 29.449 pitch_gry: 0.975
time: 243268.0 pitch_acc: 30.594 pitch_gry: 0.974
time: 243274.0 pitch_acc: 29.614 pitch_gry: 0.975
time: 243277.0 pitch_acc: 30.951 pitch_gry: 0.975
time: 243285.0 pitch_acc: 30.618 pitch_gry: 0.975
time: 243288.0 pitch_acc: 30.214 pitch_gry: 0.975
time: 243295.0 pitch_acc: 30.193 pitch_gry: 0.975
time: 243298.0 pitch_acc: 30.65 pitch_gry: 0.975
time: 243302.0 pitch_acc: 30.301 pitch_gry: 0.975